﻿using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Miris.HumanMilkAnalyser.DataModel;
using Miris.HumanMilkAnalyser.Service.Shared;
using Miris.HumanMilkAnalyser.WPF.Model;
using Miris.HumanMilkAnalyser.WPF.Shared;

namespace Miris.HumanMilkAnalyser.WPF.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class DataManagementViewModel : MyViewModelBase
    {
        public const string RequestDisplayOpenDataSourceFileDialogMessageToken = "DataManagementRequestDisplayOpenDataSourceFileDialogMessage";
        public const string RequestDisplayOpenPatientDataFileDialogMessageToken = "DataManagementRequestDisplayOpenPatientDataFileDialogMessage";
        public const string RequestDisplaySaveExportTestReportFileDialogMessageToken = "DataManagementRequestDisplaySaveExportTestReportFileDialogMessage";
        public const string RequestDisplaySaveExportMiniLogFileDialogMessageToken = "DataManagementRequestDisplaySaveExportMiniLogFileDialogMessage";
        public const string CleanDataSourceConfirmMessageToken = "DataManagementCleanDataSourceConfirmMessage";
        protected string ExportDataSourceFileFullName;
        protected string ExportPatientDataXmlFileFullName;

        /// <summary>
        /// Initializes a new instance of the PatientDataSearchViewModel class.
        /// </summary>
        public DataManagementViewModel(IDataService dataService)
            : base(dataService)
        {
            IsSqlServerCe = ConfigFileUtility.GetDataSourceType(ConfigurationConstant.ConnectionName) == DataSourceType.SqlServerCe;
        }

        protected override void RegisterMessages()
        {
            base.RegisterMessages();

            RegisterSelectedDataSourceFileMessage();
            RegisterSelectedPatientDataFileMessage();
            RegisterSelectedExportTestReportFileMessage();
        }

        public override void ResetProperties()
        {
            base.ResetProperties();

            ImportedDataSourceFile = false;
            ExportDataSourceFileName = string.Empty;
            ImportedPatientDataFile = false;
            ExportPatientDataFileName = string.Empty;
            CleanedDataSource = false;
        }

        /// <summary>
        /// The <see cref="IsSqlServerCe" /> property's name.
        /// </summary>
        public const string IsSqlServerCePropertyName = "IsSqlServerCe";

        private bool _isSqlServerCe = false;

        /// <summary>
        /// Sets and gets the IsSqlServerCe property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool IsSqlServerCe
        {
            get
            {
                return _isSqlServerCe;
            }

            set
            {
                if (_isSqlServerCe == value)
                {
                    return;
                }

                RaisePropertyChanging(IsSqlServerCePropertyName);
                _isSqlServerCe = value;
                RaisePropertyChanged(IsSqlServerCePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="ImportedDataSourceFile" /> property's name.
        /// </summary>
        public const string ImportedDataSourceFilePropertyName = "ImportedDataSourceFile";

        private bool _importedDataSourceFile = false;

        /// <summary>
        /// Sets and gets the ImportedDataSourceFile property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool ImportedDataSourceFile
        {
            get
            {
                return _importedDataSourceFile;
            }

            set
            {
                if (_importedDataSourceFile == value)
                {
                    return;
                }

                RaisePropertyChanging(ImportedDataSourceFilePropertyName);
                _importedDataSourceFile = value;
                RaisePropertyChanged(ImportedDataSourceFilePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="ExportDataSourceFileName" /> property's name.
        /// </summary>
        public const string ExportDataSourceFileNamePropertyName = "ExportDataSourceFileName";

        private string _exportDataSourceFileName = string.Empty;

        /// <summary>
        /// Sets and gets the ExportDataSourceFileName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string ExportDataSourceFileName
        {
            get
            {
                return _exportDataSourceFileName;
            }

            set
            {
                if (_exportDataSourceFileName == value)
                {
                    return;
                }

                RaisePropertyChanging(ExportDataSourceFileNamePropertyName);
                _exportDataSourceFileName = value;
                RaisePropertyChanged(ExportDataSourceFileNamePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="ExportPatientDataFileName" /> property's name.
        /// </summary>
        public const string ExportPatientDataFileNamePropertyName = "ExportPatientDataFileName";

        private string _exportPatientDataFileName = string.Empty;

        /// <summary>
        /// Sets and gets the ExportPatientDataFileName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string ExportPatientDataFileName
        {
            get
            {
                return _exportPatientDataFileName;
            }

            set
            {
                if (_exportPatientDataFileName == value)
                {
                    return;
                }

                RaisePropertyChanging(ExportPatientDataFileNamePropertyName);
                _exportPatientDataFileName = value;
                RaisePropertyChanged(ExportPatientDataFileNamePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="ImportedPatientDataFile" /> property's name.
        /// </summary>
        public const string ImportedPatientDataFilePropertyName = "ImportedPatientDataFile";

        private bool _importedPatientDataFile = false;

        /// <summary>
        /// Sets and gets the ImportedPatientDataFile property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool ImportedPatientDataFile
        {
            get
            {
                return _importedPatientDataFile;
            }

            set
            {
                if (_importedPatientDataFile == value)
                {
                    return;
                }

                RaisePropertyChanging(ImportedPatientDataFilePropertyName);
                _importedPatientDataFile = value;
                RaisePropertyChanged(ImportedPatientDataFilePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="CleanedDataSource" /> property's name.
        /// </summary>
        public const string CleanedDataSourcePropertyName = "CleanedDataSource";

        private bool _cleanedDataSource = false;

        /// <summary>
        /// Sets and gets the CleanedDataSource property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool CleanedDataSource
        {
            get
            {
                return _cleanedDataSource;
            }

            set
            {
                if (_cleanedDataSource == value)
                {
                    return;
                }

                RaisePropertyChanging(CleanedDataSourcePropertyName);
                _cleanedDataSource = value;
                RaisePropertyChanged(CleanedDataSourcePropertyName);
            }
        }

        private RelayCommand _exportDataSourceCommand;

        /// <summary>
        /// Gets the ExportDataSourceCommand.
        /// </summary>
        public RelayCommand ExportDataSourceCommand
        {
            get
            {
                return _exportDataSourceCommand
                    ?? (_exportDataSourceCommand = new RelayCommand(
                                          () =>
                                          {
                                              try
                                              {
                                                  ExportDataSourceFileFullName = ServiceFactory.CreateDataSourceManagementService().ExportDataSourceFile();
                                                  ExportDataSourceFileName = (new FileInfo(ExportDataSourceFileFullName)).Name;
                                                  ImportedDataSourceFile = false;
                                              }
                                              catch (Exception ex)
                                              {
                                                  ExportDataSourceFileName = string.Empty;
                                                  RequestDisplayErrorMessage(ex.Message);
                                              }
                                          },
                                          () => IsSqlServerCe));
            }
        }

        private RelayCommand _importDataSourceCommand;

        /// <summary>
        /// Gets the ImportDataSourceCommand.
        /// </summary>
        public RelayCommand ImportDataSourceCommand
        {
            get
            {
                return _importDataSourceCommand
                    ?? (_importDataSourceCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send RequestDisplayOpenDataSourceFileDialogMessage to DataManagementPage
                                              Messenger.Default.Send<int>(0, RequestDisplayOpenDataSourceFileDialogMessageToken);
                                          },
                                          () => IsSqlServerCe));
            }
        }

        private RelayCommand _openDataSourceFileExportDirectoryCommand;

        /// <summary>
        /// Gets the OpenDataSourceFileExportDirectoryCommand.
        /// </summary>
        public RelayCommand OpenDataSourceFileExportDirectoryCommand
        {
            get
            {
                return _openDataSourceFileExportDirectoryCommand
                    ?? (_openDataSourceFileExportDirectoryCommand = new RelayCommand(
                                          () =>
                                          {
                                              Process.Start(Directory.GetParent(ExportDataSourceFileFullName).FullName);
                                          }));
            }
        }

        private RelayCommand _exportPatientDataCommand;

        /// <summary>
        /// Gets the ExportPatientDataCommand.
        /// </summary>
        public RelayCommand ExportPatientDataCommand
        {
            get
            {
                return _exportPatientDataCommand
                    ?? (_exportPatientDataCommand = new RelayCommand(
                                          () =>
                                          {
                                              try
                                              {
                                                  ExportPatientDataXmlFileFullName = ServiceFactory.CreateDataSourceManagementService().ExportDataSourceToXMLFile();
                                                  ExportPatientDataFileName = ((new FileInfo(ExportPatientDataXmlFileFullName))).Name;
                                                  ImportedPatientDataFile = false;
                                              }
                                              catch (Exception ex)
                                              {
                                                  RequestDisplayErrorMessage(ex.Message);
                                              }
                                          }));
            }
        }

        private RelayCommand _importPatientDataCommand;

        /// <summary>
        /// Gets the ImportPatientDataCommand.
        /// </summary>
        public RelayCommand ImportPatientDataCommand
        {
            get
            {
                return _importPatientDataCommand
                    ?? (_importPatientDataCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send RequestDisplayOpenPatientDataFileDialogMessage to DataManagementPage
                                              Messenger.Default.Send<int>(0, RequestDisplayOpenPatientDataFileDialogMessageToken);
                                          }));
            }
        }

        private RelayCommand _openPatientDataXmlFileExportDirectoryCommand;

        /// <summary>
        /// Gets the OpenPatientDataXmlFileExportDirectoryCommand.
        /// </summary>
        public RelayCommand OpenPatientDataXmlFileExportDirectoryCommand
        {
            get
            {
                return _openPatientDataXmlFileExportDirectoryCommand
                    ?? (_openPatientDataXmlFileExportDirectoryCommand = new RelayCommand(
                                          () =>
                                          {
                                              Process.Start(Directory.GetParent(ExportPatientDataXmlFileFullName).FullName);
                                          }));
            }
        }

        private RelayCommand _exportTestReportCommand;

        /// <summary>
        /// Gets the ExportTestReportCommand.
        /// </summary>
        public RelayCommand ExportTestReportCommand
        {
            get
            {
                return _exportTestReportCommand
                    ?? (_exportTestReportCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send RequestDisplaySaveExportTestReportFileDialogMessage to DataManagementPage
                                              Messenger.Default.Send<int>(0, RequestDisplaySaveExportTestReportFileDialogMessageToken);
                                          }));
            }
        }

        private RelayCommand _exportMiniLogCommand;

        /// <summary>
        /// Gets the ExportMiniLogCommand.
        /// </summary>
        public RelayCommand ExportMiniLogCommand
        {
            get
            {
                return _exportMiniLogCommand
                    ?? (_exportMiniLogCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send RequestDisplaySaveExportMiniLogFileDialogMessage to DataManagementPage
                                              Messenger.Default.Send<int>(0, RequestDisplaySaveExportMiniLogFileDialogMessageToken);
                                          }));
            }
        }

        private RelayCommand<string> _cleanDataSourceCommand;

        /// <summary>
        /// Gets the CleanDataSourceCommand.
        /// </summary>
        public RelayCommand<string> CleanDataSourceCommand
        {
            get
            {
                return _cleanDataSourceCommand
                    ?? (_cleanDataSourceCommand = new RelayCommand<string>(
                                          p =>
                                          {
                                              try
                                              {
                                                  // Show a message to confirm whether user needs to clean data source.
                                                  var dialogMessage = new DialogMessage("确认清除当前数据库所有数据？该操作将不可恢复！", dialogResult =>
                                                  {
                                                      // This is the CallBack of the DialogMessage.
                                                      if (dialogResult == MessageBoxResult.Yes)
                                                      {
                                                          try
                                                          {
                                                              ServiceFactory.CreateDataSourceManagementService().CleanDataSource();
                                                              CleanedDataSource = true;
                                                          }
                                                          catch (Exception ex)
                                                          {
                                                              RequestDisplayErrorMessage(ex.Message);
                                                          }
                                                      }
                                                  })
                                                  {
                                                      Button = MessageBoxButton.YesNo,
                                                      Caption = "清除数据库",
                                                      Icon = MessageBoxImage.Question
                                                  };

                                                  Messenger.Default.Send<DialogMessage>(dialogMessage, CleanDataSourceConfirmMessageToken);
                                              }
                                              catch (Exception ex)
                                              {
                                                  RequestDisplayErrorMessage(ex.Message);
                                              }
                                          },
                                          p => p == "123"));
            }
        }

        /// <summary>
        /// Register SelectedDataSourceFileMessage from DataManagementPage.
        /// </summary>
        private void RegisterSelectedDataSourceFileMessage()
        {
            Messenger.Default.Register<string>(this, DataManagementPage.SelectedDataSourceFileMessageToken, p =>
            {
                try
                {
                    ExportDataSourceFileFullName = ServiceFactory.CreateDataSourceManagementService().ImportDataSourceFile(p);
                    ExportDataSourceFileName = (new FileInfo(ExportDataSourceFileFullName)).Name;
                    ImportedDataSourceFile = true;
                }
                catch (Exception ex)
                {
                    ExportDataSourceFileName = string.Empty;
                    RequestDisplayErrorMessage(ex.Message);
                }
            });
        }

        /// <summary>
        /// Register SelectedPatientDataFileMessage from DataManagementPage.
        /// </summary>
        private void RegisterSelectedPatientDataFileMessage()
        {
            Messenger.Default.Register<string>(this, DataManagementPage.SelectedPatientDataFileMessageToken, p =>
            {
                try
                {
                    ServiceFactory.CreateDataSourceManagementService().ImportXMLFileToDataSource(p);
                    ImportedPatientDataFile = true;
                    ExportPatientDataFileName = string.Empty;
                }
                catch (Exception ex)
                {
                    RequestDisplayErrorMessage(ex.Message);
                }
            });
        }

        /// <summary>
        /// Register SelectedExportTestReportFileMessage from DataManagementPage.
        /// </summary>
        private void RegisterSelectedExportTestReportFileMessage()
        {
            Messenger.Default.Register<string>(this, DataManagementPage.SelectedExportTestReportFileMessageToken, p =>
            {
                try
                {
                    ExportTestReport(p);
                }
                catch (Exception ex)
                {
                    RequestDisplayErrorMessage(ex.Message);
                }
            });
        }

        /// <summary>
        /// Export the patient & test result to csv file.
        /// </summary>
        /// <param name="exportTestReportFullName">The export test report csv file full name.</param>
        private void ExportTestReport(string exportTestReportFullName)
        {
            using (var fs = new FileStream(exportTestReportFullName, FileMode.Create, FileAccess.Write))
            {
                using (var sw = new StreamWriter(fs, Encoding.Unicode))
                {
                    OutputExportReportHeader(sw);
                    var patients = ServiceFactory.CreatePatientService().GetAllWithAnalysisResults();

                    foreach (var patient in patients)
                    {
                        foreach (var analysisResult in patient.AnalysisResults)
                        {
                            OutputTestResult(sw, patient, analysisResult);
                        }
                    }
                }
            }

            Process.Start(exportTestReportFullName);
        }

        /// <summary>
        /// Output the report header
        /// </summary>
        /// <param name="sw">An instance of StreamWriter.</param>
        private void OutputExportReportHeader(StreamWriter sw)
        {
            sw.WriteLine("\"编号\",\"母亲姓名\",\"年龄\",\"身高(CM)\",\"体重(KG)\",\"BMI\",\"开奶时间\",\"分娩方式\"," +
                "\"情绪\",\"不良习惯\",\"婴儿姓名\",\"出生日期\",\"性别\",\"身长(CM)\",\"体重(KG)\"," +
                "\"头围(CM)\",\"出生身长(CM)\",\"出生体重(KG)\",\"出生头围(CM)\",\"是否早产\",\"Apgar评分\",\"样本号\"," +
                "\"测试时间\",\"脂肪(g/100ml)\",\"总蛋白质(g/100ml)\",\"真蛋白质(g/100ml)\",\"糖类(g/100ml)\",\"干物质(g/100ml)\",\"总能量(kcal/100ml)\"");
        }

        /// <summary>
        /// Output the test result of one patient.
        /// </summary>
        /// <param name="sw">An instance of StreamWriter.</param>
        /// <param name="patient">The instance of Patient.</param>
        /// <param name="testTracking">The Patient's TestTracking.</param>
        private void OutputTestResult(StreamWriter sw, Patient patient, AnalysisResult analysisResult)
        {
            var singleLine = string.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\"," +
                "\"{8}\",\"{9}\",\"{10}\",\"{11}\",\"{12}\",\"{13}\",\"{14}\"," +
                "\"{15}\",\"{16}\",\"{17}\",\"{18}\",\"{19}\",\"{20}\",\"{21}\"," +
                "\"{22}\",\"{23}\",\"{24}\",\"{25}\",\"{26}\",\"{27}\",\"{28}\"",
                patient.Number, patient.MotherName, patient.MotherAge, patient.MotherHeight, patient.MotherWeight, patient.MotherBMI,
                patient.MotherOpenMilkDate.ToString(GeneralUtility.ShortDateFormat), patient.MotherDeliveryMode, patient.MotherEmotion,
                patient.MotherBadHabit, patient.BabyName, patient.BabyBirthday.ToString(GeneralUtility.ShortDateFormat),
                GeneralUtility.GetGenderDescription(patient.BabyGender), patient.BabyHeight, patient.BabyWeight, patient.BabyHeadCircumference,
                patient.BabyBirthHeight, patient.BabyBirthWeight, patient.BabyBirthHeadCircumference,
                GeneralUtility.GetIsBabyPrematureDeliveryDescription(patient.IsBabyPrematureDelivery), patient.Apgar,
                analysisResult.SampleNumber, analysisResult.TestDate.ToString(GeneralUtility.LongDateTimeFormat),
                analysisResult.Fat, analysisResult.CrudeProtein, analysisResult.TrueProtein, analysisResult.Carbohydrate,
                analysisResult.TS, analysisResult.Energy);

            sw.WriteLine(singleLine);
        }
    }
}